package com.zhoug.common.base.webview;

import android.net.Uri;
import android.net.http.SslError;
import android.os.Build;
import android.webkit.SslErrorHandler;
import android.webkit.WebResourceRequest;
import android.webkit.WebResourceResponse;
import android.webkit.WebView;
import android.webkit.WebViewClient;

import java.io.InputStream;
import java.net.URL;
import java.net.URLConnection;

import javax.net.ssl.HostnameVerifier;
import javax.net.ssl.HttpsURLConnection;
import javax.net.ssl.SSLContext;

import androidx.annotation.Nullable;
import androidx.annotation.RequiresApi;

/**
 * 支持SSL双向验证WebViewClient
 *
 * @Author 35574
 * @Date 2021/12/3
 * @Description
 */
public abstract class SslWebViewClient extends WebViewClient {
    private static final String TAG = ">>>SSlWebViewClient";
    private SSLContext mSSLContext;
    private HostnameVerifier mHostnameVerifier;

    public SslWebViewClient() {
        mSSLContext = initSSLContext();
        mHostnameVerifier = initHostnameVerifier();
    }

    /**
     * 初始化SSLContext
     *
     * @return
     */
    protected abstract SSLContext initSSLContext();

    /**
     * 初始化HostnameVerifier
     *
     * @return
     */
    protected abstract HostnameVerifier initHostnameVerifier();

    /**
     * 是否验证证书,可以根据服务器地址或其它配置处理是否需要验证证书
     *
     * @return
     */
    protected abstract boolean isCheckCerts();

    @Override
    public boolean shouldOverrideUrlLoading(WebView view, WebResourceRequest request) {
        return false;
    }

    @Override
    public void onReceivedSslError(WebView view, SslErrorHandler handler, SslError error) {
        /**
         * WebView 组件忽略 SSL 证书验证错误漏洞
         * 当发生证书认证错误时，在 WebViewClient.onReceivedSslError
         * 方法中调用默认的处理方法 handler.cancel()来停止加载问题页
         * 面。
         */
//        handler.proceed();
        handler.cancel();
    }


    @RequiresApi(api = Build.VERSION_CODES.LOLLIPOP)
    @Nullable
    @Override
    public WebResourceResponse shouldInterceptRequest(WebView view, WebResourceRequest request) {
        if (isCheckCerts()) {
            WebResourceResponse webResourceResponse = processRequest(request.getUrl());
            return webResourceResponse != null ? webResourceResponse : super.shouldInterceptRequest(view, request);
        } else {
            return super.shouldInterceptRequest(view, request);
        }
    }

    @Nullable
    @Override
    public WebResourceResponse shouldInterceptRequest(WebView view, String url) {
        if (isCheckCerts()) {
            WebResourceResponse webResourceResponse = processRequest(Uri.parse(url));
            return webResourceResponse != null ? webResourceResponse : super.shouldInterceptRequest(view, url);
        }
        return super.shouldInterceptRequest(view, url);
    }


    /**
     * 使用HttpsURLConnection发起请求
     *
     * @param uri
     * @return
     */
    protected WebResourceResponse processRequest(Uri uri) {
        //设置连接
        try {
            if (mSSLContext == null || uri == null && !uri.toString().toLowerCase().startsWith("https")) {
                return null;
            }
            URL url = new URL(uri.toString());
            URLConnection connection = url.openConnection();
            if (connection instanceof HttpsURLConnection) {
                HttpsURLConnection urlConnection = (HttpsURLConnection) connection;
                urlConnection.setSSLSocketFactory(mSSLContext.getSocketFactory());
                urlConnection.setHostnameVerifier(mHostnameVerifier);
                //获取请求的内容、contentType、encoding
                InputStream inputStream = urlConnection.getInputStream();
                String contentType = urlConnection.getContentType();
                String encoding = urlConnection.getContentEncoding();
                if (null != contentType) {
                    String mimeType = contentType;
                    if (contentType.contains(";")) {
                        mimeType = contentType.split(";")[0].trim();
                    }
                    //返回新的response
                    return new WebResourceResponse(mimeType, encoding, inputStream);
                }
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
        return null;
    }


}
